#include "ethernet.h"
#include <QDataStream>
#include <QDebug>

Ethernet::Ethernet(QObject *parent) : QObject(parent),
    tcpSocket(new QTcpSocket(this)),
    udpSocket(new QUdpSocket(this)),
    pingProcess(new QProcess(this)),
    testData(1024, 'a') // 假设每个数据包1KB
{
    connect(tcpSocket, &QTcpSocket::connected, this, &Ethernet::onConnected);
    connect(tcpSocket, &QTcpSocket::readyRead, this, &Ethernet::onReadyRead);
    connect(tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), this, &Ethernet::onError);

    connect(udpSocket, &QUdpSocket::readyRead, this, &Ethernet::onReadyRead);

    // 使用 lambda 表达式适配信号和槽的签名
    connect(pingProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
            [this](int exitCode, QProcess::ExitStatus exitStatus) { onPingFinished(); });
    connect(pingProcess, &QProcess::readyReadStandardOutput, this, &Ethernet::onPingOutput);
    connect(pingProcess, &QProcess::readyReadStandardError, this, &Ethernet::onPingError);
}

void Ethernet::connectToHost(const QString &protocol, const QString &host, quint16 port)
{
    if (protocol.toLower() == "tcp") {
        currentProtocol = "tcp";
        tcpSocket->connectToHost(host, port);
        qDebug() << "Attempting to connect to TCP host" << host << "on port" << port;
    } else if (protocol.toLower() == "udp") {
        currentProtocol = "udp";
        udpSocket->bind(QHostAddress::Any, port);
        qDebug() << "Binding UDP socket on port" << port;
    }
}

void Ethernet::sendMessage(const QString &message)
{
    if (currentProtocol == "tcp") {
        QDataStream out(tcpSocket);
        out << message;
    } else if (currentProtocol == "udp") {
        QByteArray datagram = message.toUtf8();
        udpSocket->writeDatagram(datagram, QHostAddress(tcpSocket->peerAddress()), tcpSocket->peerPort());
    }
}

void Ethernet::disconnectFromHost()
{
    if (currentProtocol == "tcp") {
        tcpSocket->disconnectFromHost();
    } else if (currentProtocol == "udp") {
        udpSocket->abort();
    }
}

void Ethernet::onReadyRead()
{
    if (isTesting) {
        if (currentProtocol == "tcp") {
            QByteArray data = tcpSocket->readAll();
            dataReceived += data.size();
        } else if (currentProtocol == "udp") {
            while (udpSocket->hasPendingDatagrams()) {
                QByteArray datagram;
                datagram.resize(udpSocket->pendingDatagramSize());
                QHostAddress sender;
                quint16 senderPort;
                udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
                dataReceived += datagram.size();
            }
        }
    } else {
        if (currentProtocol == "tcp") {
            QByteArray data = tcpSocket->readAll();
            QString message = QString::fromUtf8(data);
            emit messageReceived(message);
        } else if (currentProtocol == "udp") {
            while (udpSocket->hasPendingDatagrams()) {
                QByteArray datagram;
                datagram.resize(udpSocket->pendingDatagramSize());
                QHostAddress sender;
                quint16 senderPort;
                udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
                QString message = QString::fromUtf8(datagram);
                emit messageReceived(message);
            }
        }
    }
}

void Ethernet::onConnected()
{
    qDebug() << "TCP connection established";
    emit connectionEstablished();
}

void Ethernet::onDisconnected()
{
    qDebug() << "TCP disConnection established";
    emit connectionEstablished();
}

void Ethernet::onError(QAbstractSocket::SocketError socketError)
{
    QString errorString = tcpSocket->errorString();
    qDebug() << "Connection error:" << errorString;
    emit connectionError(errorString);
}

void Ethernet::pingHost(const QString &host)
{
    // Construct the ping command based on the operating system
#if defined(Q_OS_WIN)
    QString command = "ping -n 4 " + host;
#elif defined(Q_OS_UNIX)
    QString command = "ping -c 4 " + host;
#else
    QString command = "ping " + host;
#endif
    pingProcess->start(command);
}

void Ethernet::onPingFinished()
{
    QString output = pingProcess->readAllStandardOutput();
    QString errorOutput = pingProcess->readAllStandardError();
    if (!errorOutput.isEmpty()) {
        qDebug() << "Ping error:" << errorOutput;
        emit pingReply("Ping error: " + errorOutput);
    } else {
        qDebug() << "Ping output:" << output;
        emit pingReply("Ping output: " + output);
        // 简单的解析逻辑，可能需要根据实际输出调整
        QStringList lines = output.split("\n");
        foreach (const QString &line, lines) {
            if (line.contains("time=")) {
                QString trimmed = line.trimmed();
                int timeIndex = trimmed.indexOf("time=");
                if (timeIndex != -1) {
                    QString timeStr = trimmed.mid(timeIndex + 5);
                    qDebug() << "Ping time:" << timeStr;
                    emit pingReply("Ping time: " + timeStr);
                }
            } else if (line.contains("TTL=")) {
                QString trimmed = line.trimmed();
                int ttlIndex = trimmed.indexOf("TTL=");
                if (ttlIndex != -1) {
                    QString ttlStr = trimmed.mid(ttlIndex + 4);
                    qDebug() << "Ping TTL:" << ttlStr;
                    emit pingReply("Ping TTL: " + ttlStr);
                }
            }
        }
    }
    pingProcess->close();
}

void Ethernet::onPingOutput()
{
    QString output = pingProcess->readAllStandardOutput();
    qDebug() << "Ping output:" << output;
    emit pingReply("Ping output: " + output);
    // 简单的解析逻辑，可能需要根据实际输出调整
    QStringList lines = output.split("\n");
    foreach (const QString &line, lines) {
        if (line.contains("time=")) {
            QString trimmed = line.trimmed();
            int timeIndex = trimmed.indexOf("time=");
            if (timeIndex != -1) {
                QString timeStr = trimmed.mid(timeIndex + 5);
                qDebug() << "Ping time:" << timeStr;
                emit pingReply("Ping time: " + timeStr);
            }
        } else if (line.contains("TTL=")) {
            QString trimmed = line.trimmed();
            int ttlIndex = trimmed.indexOf("TTL=");
            if (ttlIndex != -1) {
                QString ttlStr = trimmed.mid(ttlIndex + 4);
                qDebug() << "Ping TTL:" << ttlStr;
                emit pingReply("Ping TTL: " + ttlStr);
            }
        }
    }
}

void Ethernet::onPingError()
{
    QString errorOutput = pingProcess->readAllStandardError();
    qDebug() << "Ping error:" << errorOutput;
    emit pingReply("Ping error: " + errorOutput);
}

void Ethernet::startSpeedTest(const QString &protocol, const QString &host, quint16 port, int duration)
{
    connectToHost(protocol, host, port);
    isTesting = true;
    startTime.start();
    testHost = host; // 初始化 testHost
    testPort = port; // 初始化 testPort
    QTimer::singleShot(duration * 1000, this, &Ethernet::stopSpeedTest); // 设置定时器，在指定时间后停止测试
    sendData(); // 开始发送数据
}

void Ethernet::sendData()
{
    if (!isTesting || !tcpSocket->isOpen()) return;
    if (currentProtocol == "tcp") {
        tcpSocket->write(testData);
        dataSent += testData.size();
    } else if (currentProtocol == "udp") {
        udpSocket->writeDatagram(testData, QHostAddress(testHost), testPort);
        dataSent += testData.size();
    }
    QTimer::singleShot(0, this, &Ethernet::sendData); // 使用0延迟的定时器连续发送数据
}

void Ethernet::stopSpeedTest()
{
    isTesting = false;
    endTime = QTime::currentTime();
    calculateSpeed();
}

void Ethernet::calculateSpeed()
{
    int elapsedTime = startTime.msecsTo(endTime);
    double sentMbps = (dataSent * 8.0) / (elapsedTime / 1000.0) / 1024 / 1024; // 计算发送速率，单位为Mbps
    double receivedMbps = (dataReceived * 8.0) / (elapsedTime / 1000.0) / 1024 / 1024; // 计算接收速率，单位为Mbps
    qDebug() << "Sent Speed: " << sentMbps << " Mbps, Received Speed: " << receivedMbps << " Mbps";
    emit speedTestResult(sentMbps, receivedMbps);
}
